package com.tech.mapper.tem.imp;

import com.tech.mapper.GoodsDao;
import com.tech.repository.dto.GoodsInfo;
import com.tech.repository.entity.Goods;
import com.tech.repository.entity.GoodsImage;
import com.tech.util.FileUtil;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

public class GoodsDaoMysqlImp extends BasicDaoImp<Goods> implements GoodsDao {
	@Override
	public Goods getGoods(int id) {
		// TODO 通过ID进行的操作不少都是重复的，应该可以通过泛型将公共方法提取出来
		SqlTask<Integer, Goods> sqlTask = (item, data) -> {
			String sql = "select * from goodsinfo where gid=?";
			Goods goods = null;
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setInt(1, data);
			ResultSet rs = item.executeQuery();
			if (rs.next()) {
				goods = getInstance(rs);
			}
			return goods;
		};
		// 执行sql语句
		return SqlTask.processSql(sqlTask, id);
	}

	@Override
	public List<Goods> getUserGoods(int userId) {
		SqlTask<Integer, List<Goods>> sqlTask = (item, data) -> {
			String sql = "select * from goodsinfo where uid=?";
			ArrayList<Goods> list = new ArrayList<>();
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setInt(1, data);
			ResultSet rs = item.executeQuery();
			while (rs.next()) {
				list.add(getInstance(rs));
			}
			return list;
		};
		return SqlTask.processSql(sqlTask, userId);
	}

	@Override
	public int getGoodsCount() {
		SqlTask<Object, Integer> sqlTask = (item, data) -> {
			String sql = "select count(*) from goodsinfo";
			item.prepareStatement(sql);
			ResultSet rs = item.executeQuery();
			if (rs.next())
				return rs.getInt(1);
			return -1;
		};
		return SqlTask.processSql(sqlTask, null);
	}

	@Override
	public List<Goods> getGoods(int beginIndex, int count) {
		SqlTask<Object, List<Goods>> sqlTask = (item, data) -> {
			String sql = "select * from goodsinfo limit ?,?";
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setInt(1, beginIndex);
			statement.setInt(2, count);
			ResultSet rs = item.executeQuery();
			List<Goods> list = new ArrayList<>();
			while (rs.next()) {
				list.add(getInstance(rs));
			}
			return list;
		};
		return SqlTask.processSql(sqlTask, null);
	}

	@Override
	public GoodsInfo getGoodsInfo(int goodsId) {
		SqlTask<Integer, GoodsInfo> sqlTask = (item, data) -> {
			String sql = "select goodsinfo.*, imid, image from goodsinfo left outer join goodsimage g on goodsinfo.gid = g.gid where goodsinfo.gid = ?";
			GoodsInfo goodsInfo = null;
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setInt(1, data);
			ResultSet rs = item.executeQuery();
			ArrayList<GoodsImage> images = new ArrayList<>();
			while (rs.next()) {
				if (goodsInfo == null) {
					goodsInfo = new GoodsInfo(getInstance(rs), images);
				}
				if (rs.getBytes("image") != null) //图片不为空才添加
					images.add(getGoodsImage(rs));
			}
			return goodsInfo;
		};
		return SqlTask.processSql(sqlTask, goodsId);
	}

	@Override
	public TreeMap<Integer, List<Goods>> getAllGoods() {
		SqlTask<Object, TreeMap<Integer, List<Goods>>> sqlTask = (item, data) -> {
			String sql = "select * from goodsinfo order by uid";
			TreeMap<Integer, List<Goods>> map = new TreeMap<>();
			int lastId = -1;
			item.prepareStatement(sql);
			ResultSet rs = item.executeQuery();
			ArrayList<Goods> list = null;
			while (rs.next()) {
				if (rs.getInt("uid") != lastId) {
					if (lastId != -1)
						map.put(lastId, list);
					list = new ArrayList<>();
					lastId = rs.getInt("uid");
				}
				assert list != null;
				list.add(getInstance(rs));
			}
			if (lastId != -1)
				map.put(lastId, list);
			return map;
		};
		return SqlTask.processSql(sqlTask, null);
	}

	@Override
	public int addGoods(Goods goods) {
		SqlTask<Goods, Integer> sqlTask = (item, data) -> {
			String sql = "insert into goodsinfo(gname, gpopularity, gintroduce,sid,gprice,gsecprice,gcondition,uid,uname,gcount,gsendmode,gcreatetime) values " +
					"(?,?,?,?,?,?,?,?,?,?,?,?)";
			int newId = -1;
			PreparedStatement statement = item.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
			statement.setString(1, data.getName());
			statement.setInt(2, data.getPopularity());
			statement.setString(3, data.getIntroduce());
			statement.setInt(4, data.getSortId());
			statement.setDouble(5, data.getPrice());
			statement.setDouble(6, data.getSecondPrice());
			statement.setString(7, data.getCondition().toString());
			statement.setInt(8, data.getSellerId());
			statement.setString(9, goods.getSellerName());
			statement.setInt(10, data.getCount());
			statement.setString(11, data.getSendMode().toString());
			statement.setDate(12, new Date(data.getCreateTime().getTime())); //需要传入sql.Date对象，这里需要转换一下
			if (statement.executeUpdate() == 1) {
				ResultSet generatedKeys = item.getGeneratedKeys();
				if (generatedKeys.next()) {
					newId = generatedKeys.getInt(1);
				}
			}
			return newId;
		};
		return SqlTask.processSql(sqlTask, goods);
	}

	@Override
	public int[] addGoods(List<Goods> goodsList) {
		SqlTask<List<Goods>, int[]> sqlTask = (item, data) -> {
			String sql = "insert into goodsinfo(gname, gpopularity, gintroduce,sid,gprice,gsecprice,gcondition,uid,uname,gcount,gcreatetime) values " +
					"(?,?,?,?,?,?,?,?,?,?,?)";
			int[] result = null;
			PreparedStatement statement = item.prepareStatement(sql);
			for (Goods goods : data) {
				statement.setString(1, goods.getName());
				statement.setInt(2, goods.getPopularity());
				statement.setString(3, goods.getIntroduce());
				statement.setInt(4, goods.getSortId());
				statement.setDouble(5, goods.getPrice());
				statement.setDouble(6, goods.getSecondPrice());
				statement.setString(7, goods.getCondition().toString());
				statement.setInt(8, goods.getSellerId());
				statement.setString(9, goods.getSellerName());
				statement.setInt(10, goods.getCount());
				statement.setDate(11, new Date(goods.getCreateTime().getTime()));
				statement.addBatch();
			}
			result = statement.executeBatch();
			return result;
		};
		return SqlTask.processSql(sqlTask, goodsList);
	}

	@Override
	public boolean delGoods(int id) {
		SqlTask<Integer, Boolean> sqlTask = (item, data) -> {
			String sql = "delete from goodsinfo where gid = ?";
			boolean result = false;
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setInt(1, data);
			if (statement.executeUpdate() > 0) {
				result = true;
			}
			return result;
		};
		return SqlTask.processSql(sqlTask, id);
	}

	@Override
	public int[] delGoods(List<Integer> goodsList) {
		SqlTask<List<Integer>, int[]> sqlTask = (item, data) -> {
			String sql = "delete from goodsinfo where gid = ?";
			int[] result = null;
			PreparedStatement statement = item.prepareStatement(sql);

			for (Integer goodsId : data) {
				statement.setInt(1, goodsId);
				statement.addBatch();
			}
			result = statement.executeBatch();
			return result;
		};
		return SqlTask.processSql(sqlTask, goodsList);
	}

	@Override
	public int delUserGoods(int userId) {
		SqlTask<Integer, Integer> sqlTask = (item, data) -> {
			String sql = "delete from goodsinfo where uid = ?";
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setInt(1, data);
			return statement.executeUpdate();
		};
		return SqlTask.processSql(sqlTask, userId);
	}

	@Override
	public boolean delAllGoods() {
		SqlTask<Object, Boolean> sqlTask = (item, data) -> {
			String sql = "delete from goodsinfo where true";
			PreparedStatement statement = item.prepareStatement(sql);
			statement.executeUpdate();
			return true;
		};
		return SqlTask.processSql(sqlTask, null);
	}

	@Override
	public boolean updateGoods(int goodId, Goods editedGoods) {
		SqlTask<Object, Boolean> sqlTask = (item, data) -> {
			String sql = "update goodsinfo set gname = ?,gintroduce = ?,sid = ?,gprice = ?,gsecprice = ?,gcondition = ?,gcount = ?,gsendmode = ? where gid = ?";
			PreparedStatement statement = item.prepareStatement(sql);
			statement.setString(1, editedGoods.getName());
			statement.setString(2, editedGoods.getIntroduce());
			statement.setInt(3, editedGoods.getSellerId());
			statement.setDouble(4, editedGoods.getPrice());
			statement.setDouble(5, editedGoods.getSecondPrice());
			statement.setString(6, editedGoods.getCondition().toString());
			statement.setInt(7, editedGoods.getCount());
			statement.setString(8, editedGoods.getSendMode().toString());
			statement.setInt(9, goodId);
			return statement.executeUpdate() > 0;
		};
		return SqlTask.processSql(sqlTask, null);
	}

	@Override
	protected Goods getInstance(ResultSet rs) throws SQLException {
		return new Goods(rs.getInt("gid"),
				rs.getString("gname"),
				rs.getInt("gpopularity"),
				rs.getString("gintroduce"),
				rs.getInt("sid"),
				rs.getDouble("gprice"),
				rs.getDouble("gsecprice"),
				rs.getInt("uid"),
				Goods.Condition.parse(rs.getString("gcondition")),
				Goods.SendMode.parse(rs.getString("gsendmode")),
				rs.getString("uname"),
				rs.getInt("gcount"),
				rs.getDate("gcreatetime"));
	}

	private GoodsImage getGoodsImage(ResultSet rs) throws SQLException {
		return new GoodsImage(rs.getInt("imid"),
				rs.getInt("gid"),
				"png",
				FileUtil.byteToImage(rs.getBytes("image")));
	}
}
